package com.iteaj.iot.server.dtu;

import com.iteaj.iot.CoreConst;
import com.iteaj.iot.server.ServerMessage;
import com.iteaj.iot.server.dtu.message.DtuMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.Attribute;

/**
 * dtu 上电第一包设备编号解码器<hr>
 *     1. 此handler要求dtu上报的第一包必须是设备编号
 *     2. 后面的报文如果内容和设备编号一致则作为心跳报文
 */
public class DtuFirstDeviceSnPackageHandler extends ChannelInboundHandlerAdapter {

    private DtuMessageDecoder messageDecoder;

    public DtuFirstDeviceSnPackageHandler(DtuMessageDecoder messageDecoder) {
        this.messageDecoder = messageDecoder;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(msg instanceof ByteBuf) {
            ByteBuf buf = (ByteBuf) msg;
            if(buf.readableBytes() > 0) {
                Attribute attr = ctx.channel().attr(CoreConst.EQUIP_CODE);
                if (attr.get() == null) { // 设备编号不存在说明是DTU第一次上报设备编号
                    buildDeviceSnMessage(ctx, buf);
                } else {
                    while (buf.readableBytes() > 0) {
                        byte[] message = new byte[buf.readableBytes()];
                        // 标记读索引
                        // 解码异常 #I51ASQ
                        buf.markReaderIndex().readBytes(message);

                        // 如果dtu除了上报设备编号的报文外, dtu自身还有其他的功能(心跳或者AT指令)
                        // 注：需要开发者自己做粘包处理
                        ServerMessage serverMessage = messageDecoder.decodeBefore((String) attr.get(), message, buf);
                        if (serverMessage != null) {
                            buf.release();
                            serverMessage.setChannelId(ctx.channel().id().asShortText());
                            super.channelRead(ctx, serverMessage.readBuild());
                        } else {
                            // 恢复读索引
                            // 解码异常 #I51ASQ
                            buf.resetReaderIndex();
                            super.channelRead(ctx, msg);
                        }
                    }
                }
            }
        } else {
            super.channelRead(ctx, msg);
        }
    }

    /**
     * 构建Dtu设备的第一个报文(上报设备编号)
     * @param ctx
     * @param buf
     * @throws Exception
     */
    private void buildDeviceSnMessage(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {
        try {
            byte[] message = new byte[buf.readableBytes()];
            buf.readBytes(message);
            String deviceSn = messageDecoder.resolveEquipCode(message);

            // 由于第一包是字符串类型的设备编号 不执行读构建{@link SocketMessage#readBuild()}
            ServerMessage dtuMessage = messageDecoder.createMessage(message);

            // 设置设备编号
            ((DtuMessage) dtuMessage).setEquipCode(deviceSn);

            // 设置DTU报文头
            dtuMessage.setHead(((DtuMessage) dtuMessage).buildFirstHead());

            // 交由下一个handler
            super.channelRead(ctx, dtuMessage);
        } finally {
            buf.release(); // 释放已经读取的二进制数据
        }
    }

}
